#include "MVTKWidget.h"

MVtkWidget::MVtkWidget(QWidget * parent):
	QVTKOpenGLNativeWidget(parent)
{
	Renderer = vtkSmartPointer<vtkRenderer>::New();
	Renderer->SetBackground(0.3,0.3,0.3);
	Renderer->SetBackground2(1.0,1.0,1.0);
	Renderer->SetGradientBackground(true);
	renderWindow()->AddRenderer(this->Renderer);

	vtkNew<MInteractorStyle> interactor;
	interactor->setHighLightMode(HighLightByBound);
	interactor->SetDefaultRenderer(this->Renderer);
	this->interactor()->SetInteractorStyle(interactor);

	// 初始化角落坐标系
	vtkNew<vtkAxesActor> axisActor;
	axisActor->SetShaftType(0);

	this->AxisWidget = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
	this->AxisWidget->SetOrientationMarker(axisActor);
	this->AxisWidget->SetInteractor(renderWindow()->GetInteractor());
	this->AxisWidget->SetViewport(0.0,0.0,0.1,0.2);
	this->AxisWidget->SetEnabled(1);
	this->AxisWidget->InteractiveOff();

	this->Connector = vtkSmartPointer<vtkEventQtSlotConnect>::New();
	this->WorldPicker = vtkSmartPointer<vtkWorldPointPicker>::New();
	//Connector->Connect(this->interactor(), vtkCommand::LeftButtonPressEvent, this, SLOT(highLightActor()));

	ViewAXO();
}

MVtkWidget::~MVtkWidget()
{}

TopoDS_Shape MVtkWidget::getOCCByActor(vtkActor * actor)
{
	IVtkOCC_Shape::Handle iShape = IVtkTools_ShapeObject::GetOccShape(actor);
	TopoDS_Shape shape = iShape->GetShape();
	return shape;
}

void MVtkWidget::updateRenders()
{
	renderWindow()->Render();
}

void MVtkWidget::removeAll()
{
	vtkActorCollection* actors = Renderer->GetActors();

	actors->InitTraversal();
	vtkActor* actor;
	while((actor = actors->GetNextActor()) != nullptr)
	{
		Renderer->RemoveActor(actor);
	}
	updateRenders();
}

void MVtkWidget::removeActor(vtkActor* actor)
{
	Renderer->RemoveActor(actor);
}

void MVtkWidget::fitAll()
{
	Renderer->ResetCamera();
	Renderer->ResetCameraClippingRange();
	updateRenders();
}

void MVtkWidget::fitActor(vtkActor * actor)
{
	Renderer->ResetCamera(actor->GetBounds());
}

void MVtkWidget::disPlayOCC(TopoDS_Shape & aShape)
{
	if(aShape.IsNull())
		qDebug() << "shape err";
	IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(aShape);
	vtkNew<IVtkTools_ShapeDataSource> DS;
	DS->SetShape(aShapeImpl);
	DS->Update();
	vtkNew<IVtkTools_DisplayModeFilter> filter;
	filter->SetInputData(DS->GetOutput());
	filter->SetDisplayMode(DM_Shading);
	filter->SetSmoothShading(1);
	filter->Update();
	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputData(filter->GetOutput());

	vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
	initStyleActor(actor);
	Renderer->AddActor(actor);
}

void MVtkWidget::disPlayOCCByLowLevel(TopoDS_Shape & aShape)
{
	IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(aShape);
	IVtkVTK_ShapeData::Handle aDataImpl = new IVtkVTK_ShapeData();
	IVtk_IShapeMesher::Handle aMesher = new IVtkOCC_ShapeMesher();
	aMesher->Build (aShapeImpl,aDataImpl);
	vtkPolyData* aPolyData = aDataImpl->getVtkPolyData();
	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputData(aPolyData);

	vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
	initStyleActor(actor);
	Renderer->AddActor(actor);
}

void MVtkWidget::setEdgeVisibleAll(bool visible)
{
	vtkActorCollection* actors = Renderer->GetActors();

	actors->InitTraversal();
	vtkActor* actor;
	while((actor = actors->GetNextActor()) != nullptr)
	{
		actor->GetProperty()->SetEdgeVisibility(visible);
	}
}

void MVtkWidget::ViewAXO()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(-1,-1,-1);
	Renderer->GetActiveCamera()->SetViewUp(0,0,1);

	fitAll();
}

void MVtkWidget::ViewPositiveX()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(1,0,0);
	Renderer->GetActiveCamera()->SetViewUp(0,0,1);

	fitAll();
}

void MVtkWidget::ViewPositiveY()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(0,1,0);
	Renderer->GetActiveCamera()->SetViewUp(0,0,1);

	fitAll();
}

void MVtkWidget::ViewPositiveZ()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(0,0,1);
	Renderer->GetActiveCamera()->SetViewUp(0,1,0);

	fitAll();
}

void MVtkWidget::ViewNegativeX()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(-1,0,0);
	Renderer->GetActiveCamera()->SetViewUp(0,0,1);

	fitAll();
}

void MVtkWidget::ViewNegativeY()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(0,-1,0);
	Renderer->GetActiveCamera()->SetViewUp(0,0,1);

	fitAll();
}

void MVtkWidget::ViewNegativeZ()
{
	Renderer->GetActiveCamera()->SetPosition(0,0,0);
	Renderer->GetActiveCamera()->SetFocalPoint(0,0,-1);
	Renderer->GetActiveCamera()->SetViewUp(0,1,0);

	fitAll();
}

void MVtkWidget::initStyleActor(vtkActor * actor)
{
	actor->GetProperty()->SetEdgeVisibility(true);
	actor->GetProperty()->SetLineWidth(1);
}

vtkStandardNewMacro(MInteractorStyle);

MInteractorStyle::MInteractorStyle():
	currentHighLightMode(HighLightByColor)
{
	picker = vtkSmartPointer<vtkPropPicker>::New();
}

MInteractorStyle::~MInteractorStyle()
{

}

void MInteractorStyle::OnLeftButtonDown()
{
	highLightBySelect();

	// Forward events.
	//vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
}

void MInteractorStyle::OnRightButtonDown()
{
	if(this->Interactor->GetShiftKey())
	{
		this->StartRotate();
	} else
	{
		vtkInteractorStyleTrackballCamera::OnRightButtonDown();
	}
}

void MInteractorStyle::OnRightButtonUp()
{
	if(this->State == VTKIS_ROTATE)
	{
		this->EndRotate();
	} else
	{
		vtkInteractorStyleTrackballCamera::OnRightButtonUp();
	}
}

void MInteractorStyle::OnMouseMove()
{
	if (State != VTKIS_ROTATE && State != VTKIS_PAN)
		highLightByDetect();
	vtkInteractorStyleTrackballCamera::OnMouseMove();
}

void MInteractorStyle::setHighLightMode(HighLightMode mode)
{
	currentHighLightMode = mode;
}

void MInteractorStyle::highLightBySelect()
{
	int* clickPos = this->GetInteractor()->GetEventPosition();
	picker->Pick(clickPos[0],clickPos[1],0,this->GetDefaultRenderer());
	vtkSmartPointer<vtkActor> pickedActor = vtkSmartPointer<vtkActor>::New();
	pickedActor = picker->GetActor();
	if(pickedActor)
	{
		auto it = std::find(pickedActors.begin(),pickedActors.end(),pickedActor);
		if(it != pickedActors.end() && this->Interactor->GetControlKey())
		{
			int i = it- pickedActors.begin();
			pickedActor->GetProperty()->DeepCopy(pickedPropertys[i]);
			pickedActors.erase(it);
			pickedPropertys.erase(pickedPropertys.begin() + i);
		}
		else if (it == pickedActors.end())
		{
			pickedActors.push_back(pickedActor);
			vtkSmartPointer<vtkProperty> pickedProperty = vtkSmartPointer<vtkProperty>::New();
			pickedProperty->DeepCopy(pickedActor->GetProperty());
			pickedPropertys.push_back(pickedProperty);

			vtkNew<vtkNamedColors> colors;
			pickedActor->GetProperty()->SetColor(colors->GetColor3d("Red").GetData());
			pickedActor->GetProperty()->SetDiffuse(1.0);
			pickedActor->GetProperty()->SetSpecular(0.0);
			pickedActor->GetProperty()->EdgeVisibilityOn();
		}
	}
	else
	{
		int i = 0;
		for(auto pickedActor: pickedActors)
		{
			pickedActor->GetProperty()->DeepCopy(pickedPropertys[i]);
			++i;
		}
		pickedActors.clear();
		pickedPropertys.clear();
	}

	this->GetDefaultRenderer()->GetRenderWindow()->Render();
}

void MInteractorStyle::highLightByDetect()
{
	int* clickPos = this->GetInteractor()->GetEventPosition();
	picker->Pick(clickPos[0],clickPos[1],0,this->GetDefaultRenderer());
	vtkSmartPointer<vtkActor> pickedActor = picker->GetActor();

	// 如果检测到的 actor 没有变化，则不进行任何操作
	if(pickedActor == detectActor)
	{
		return;
	}

	// 移除之前的高亮 actor
	if(detectActor)
	{
		this->GetDefaultRenderer()->RemoveActor(detectActor);
		detectActor = nullptr;
	}

	if(pickedActor)
	{
		vtkNew<vtkOutlineSource> outlineSource;
		outlineSource->SetBounds(pickedActor->GetBounds());
		vtkNew<vtkPolyDataMapper> outlineMapper;
		outlineMapper->SetInputConnection(outlineSource->GetOutputPort());
		detectActor = vtkSmartPointer<vtkActor>::New();
		detectActor->SetMapper(outlineMapper);
		detectActor->GetProperty()->SetColor(1.0,0.0,0.0);
		detectActor->GetProperty()->SetLineWidth(2);
		this->GetDefaultRenderer()->AddActor(detectActor);
	}

	this->GetDefaultRenderer()->GetRenderWindow()->Render();
}
